<?php
namespace core\db;
use mysqli_result;
use ReflectionClass;

class Orm
{
    public $setArr = [];

    public static $isWith = 0;

    public static $saveData = [];

    private static $modelObj;

    private static $otherModelObj;

    private static $otherModelObjs;

    private static $instance;

    protected static $table;

    private static $where;
    private static $conn;
    private static $filed;
    private static $alias;
    private static $order;
    private static $limit;
    private static $group;
    private static $join;


    public function __construct($table = '')
    {
        if (!empty($table)){
            self::$table = $table;
        }
//        $config = getMysqlConfig();
//        $link = mysqli_connect("{$config['host']}:{$config['port']}", $config['username'], $config['password']);
        $link = mysqli_connect("39.105.13.244:3306", "diary", "HbfWETZbrN8nbwiP");
        if (!$link) {
            echo "连接数据库失败";exit;
        }
        mysqli_select_db($link, "diary");
        self::$conn = $link;
    }

    public function __set($k ,$v)
    {
        $this->setArr[$k] = $v;
    }

    public function __get($k)
    {
        return self::$saveData[$k];
    }

    /**
     * 一对多查询
     * @param $class
     * @param $forKey
     * @param string $localKey
     * @return array|void
     */
    public function hasMany($class, $forKey, $localKey = 'id')
    {
        $mainTable = self::$table;
        //实例化后，self table 将会被改变
        $obj = new $class;
        self::$otherModelObj = $obj;

        $outSideTable = $obj->tables;
        self::$table = $mainTable;
        if (isset(self::$saveData['id']) && !empty(self::$saveData['id'])){
            self::$where = "where {$mainTable}.{$localKey} = ".self::$saveData['id'];
        }
        self::$join = "join $outSideTable on {$mainTable}.$localKey = {$outSideTable}.{$forKey}";
        if (self::$isWith == 0){
            return self::select();
        }
        //重置
        self::$isWith = 0;
    }

    /**
     * 一对一查询
     * @param $class
     * @param $forKey
     * @param string $localKey
     * @return array|void
     */
    public function hasOne($class, $forKey, $localKey = 'id')
    {
        $mainTable = self::$table;
        //实例化后，self table 将会被改变
        $obj = new $class;

        self::$otherModelObj = $obj;
        $outSideTable = $obj->tables;
        self::$table = $mainTable;
        if (isset(self::$saveData['id']) && !empty(self::$saveData['id'])){
            self::$where = "where {$mainTable}.{$localKey} = ".self::$saveData['id'];
        }
        self::$join = "join $outSideTable on {$mainTable}.$localKey = {$outSideTable}.{$forKey}";
        if (self::$isWith == 0){
            return self::find();
        }
        //重置
        self::$isWith = 0;
    }

    /**
     * 远程关联
     * @param $class
     * @param $otherClass
     * @param $localKey
     * @param $forKey
     * @param $otherKey
     * @return array|void
     */
    public function hasManyThrough($class, $otherClass, $localKey, $forKey, $otherKey)
    {
        $mainTable = self::$table;
        //实例化后，self table 将会被改变
        $obj = new $class;
        self::$otherModelObj = $obj;
        $outSideTable = $obj->tables;

        $otherObj = new $otherClass;
        self::$otherModelObjs = $otherObj;
        $otherOutSideTable = $otherObj->tables;


        self::$table = $mainTable;
        if (isset(self::$saveData['id']) && !empty(self::$saveData['id'])){
            self::$where = "where {$mainTable}.{$localKey} = ".self::$saveData['id'];
        }
        if ($forKey == $otherKey){
            self::$join = "join $outSideTable on {$mainTable}.$localKey = {$outSideTable}.{$forKey} join $otherOutSideTable on {$mainTable}.$localKey = {$otherOutSideTable}.{$otherKey}";
        }else{
            self::$join = "join $outSideTable on {$mainTable}.$localKey = {$outSideTable}.{$forKey} join $otherOutSideTable on {$outSideTable}.id = {$otherOutSideTable}.{$otherKey}";
        }
        if (self::$isWith == 0){
            return self::select();
        }
        //重置
        self::$isWith = 0;
    }

    /**
     * 关联查询
     * @param $func
     * @return Orm
     */
    public static function with($func)
    {
        self::$saveData = [];
        self::handleTable();
        if(!(self::$instance instanceof self))
        {
            self::$instance = new self();
        }
        self::$isWith = 1;


        $class = get_called_class();
        $obj = new $class;

        self::$otherModelObj = $obj;

        $obj->$func();
        return self::$instance;
    }

    /**
     * 保存或修改数据
     * @param array $data
     * @return bool|mysqli_result|void
     */
    public function save($data = [])
    {
        if (empty($data)){
            $data = $this->setArr;
        }
        $arr = self::assembleField();
        if (isset(self::$saveData['id'])){
            //进行修改
            $str = '';
            foreach ($data as $key => $value) {
                if ($key == 'id') continue;
                $str .= "$key = '{$value}',";
            }
            //截取字符串最后一位
            $str = mb_substr($str,0,mb_strlen($str)-1);
            $where = 'where id = '.self::$saveData['id'];
            $sql = "update {$arr['table']} set {$str} {$where}";
            return mysqli_query(self::$conn, $sql);
        }else{
            //进行添加
            if($data){
                $keys = "";
                $values = '';
                foreach ($data as $key => $value) {
                    $keys .= "`".$key."`,";
                    $values .= "'".$value."',";
                }
                $keys = rtrim($keys,',');
                $values = rtrim($values,',');
                $sql = "INSERT INTO `{$arr['table']}`({$keys}) VALUES({$values})";
                return mysqli_query(self::$conn, $sql);
            }
        }
    }

    /**
     * 删除数据
     * @return bool|mysqli_result
     */
    public function delete()
    {
        $arr = self::assembleField();
        if (isset(self::$saveData['id']) && !empty(self::$saveData['id'])){
            $arr['where'] = 'where id = '.self::$saveData['id'];
        }
        $sql = "DELETE FROM `{$arr['table']}` {$arr['where']}";
        return mysqli_query(self::$conn, $sql);
    }

    /**
     * 根据主键删除数据
     * @param $id
     * @return bool|mysqli_result
     */
    public static function destroy($id)
    {
        self::handleTable();
        $arr = self::assembleField();
        $sql = "DELETE FROM `{$arr['table']}` where id = {$id}";
        return mysqli_query(self::$conn, $sql);
    }

    /**
     * 查询指定的字段
     * @param $filed
     * @return $this
     */
    public static function field($filed)
    {
        self::handleTable();
        if(!(self::$instance instanceof self))
        {
            self::$instance = new self();
        }
        self::$filed = $filed;
        return self::$instance;
    }

    /**
     * 表名起别名
     * @param $name
     * @return $this
     */
    public static function alias($name)
    {
        self::handleTable();
        if(!(self::$instance instanceof self))
        {
            self::$instance = new self();
        }
        self::$alias = $name;
        return self::$instance;
    }

    /**
     * 限制数据条数
     * @param $number
     * @return $this
     */
    public static function limit($number)
    {
        self::handleTable();
        if(!(self::$instance instanceof self))
        {
            self::$instance = new self();
        }
        $str = "limit $number";
        self::$limit = $str;
        return self::$instance;
    }

    /**
     * 分组数据
     * @param $filed
     * @return $this
     */
    public static function group($filed)
    {
        self::handleTable();
        if(!(self::$instance instanceof self))
        {
            self::$instance = new self();
        }
        $str = "";
        if (is_array($filed)){
            $filedStr = implode(',',$filed);
            $str = "group by $filedStr";
        }elseif (is_string($filed)&&!empty($filed)){
            $str = "group by $filed";
        }
        self::$group = $str;
        return self::$instance;
    }

    /**
     * where 条件
     * @param $field
     * @param $exp
     * @param $val
     * @return Orm
     */
    public static function where($field, $exp, $val)
    {
        self::handleTable();
        if(!(self::$instance instanceof self))
        {
            self::$instance = new self();
        }
        if ($exp == 'in'){
            if (!empty(self::$where)){
                self::$where .= " and ".$field.' '.$exp.' '."($val)";
            }else{
                self::$where = "where ".$field.' '.$exp.' '."($val)";
            }
        }else{
            if (!empty(self::$where)){
                self::$where .= " and ".$field.' '.$exp.' '."'$val'";
            }else{
                self::$where = "where ".$field.' '.$exp.' '."'$val'";
            }
        }
        return self::$instance;
    }

    /**
     * 查询排序
     * @param $field
     * @param string $exp
     * @return Orm
     */
    public static function order($field, $exp = 'asc')
    {
        self::handleTable();
        if(!(self::$instance instanceof self))
        {
            self::$instance = new self();
        }
        $str = "order by ".$field." $exp";
        self::$order = $str;
        return self::$instance;
    }

    /**
     * 查询单条
     * @return array
     */
    public static function find($id = 0)
    {
        self::handleTable();
        if (self::$filed == null || empty(self::$filed)){
            self::$filed = '*';
        }
        if ($id){
            self::$where = "where ".'id'.' '.'='.' '."($id)";
        }

        $arr = self::assembleField();
        $sql = "select {$arr['field']} from {$arr['table']} {$arr['alias']} {$arr['join']} {$arr['where']} {$arr['group']} {$arr['order']} {$arr['limit']}";
        $data = self::executeOne($sql);
        if (!empty($data)){
            $data = self::handleModelData($data);
        }
        if ($id){
            self::$saveData = $data;
            return self::$modelObj;
        }else{
            return $data;
        }
    }

    /**
     * 查询全部
     * @return array
     */
    public static function select()
    {
        self::handleTable();
        if (self::$filed == null || empty(self::$filed)){
            self::$filed = '*';
        }
        $arr = self::assembleField();
        $sql = "select {$arr['field']} from {$arr['table']} {$arr['alias']} {$arr['join']} {$arr['where']} {$arr['group']} {$arr['order']} {$arr['limit']}";
        $data = self::executeAll($sql);
        if (!empty($data)){
            $data = self::handleModelData($data);
        }
        return $data;
    }

    /**
     * 执行单条查询
     * @param $sql
     * @return array|false|string[]|void|null
     */
    private static function executeOne($sql)
    {
        $result = mysqli_query(self::$conn, $sql);
        if ($result == false){
            return ;
        }
        self::clearParam();
        return mysqli_fetch_assoc($result);
    }

    /**
     * 执行全部查询
     * @param $sql
     * @return array|void
     */
    private static function executeAll($sql)
    {
        $result = mysqli_query(self::$conn, $sql);
        if ($result == false){
            return ;
        }
        self::clearParam();
        $arr = [];
        while ($row = mysqli_fetch_assoc($result)){
            $arr[] = $row;
        }
        return $arr;
    }


    /**
     * 处理模型数据
     * @param $data
     * @return array
     */
    private static function handleModelData($data)
    {
        $method = get_class_methods(self::$modelObj);
        $otherMethod = get_class_methods(self::$otherModelObj);
        $otherMethods = get_class_methods(self::$otherModelObjs);
        if (!empty($method)){
            $data = self::handleData($data, $method, self::$modelObj);
        }
        if (!empty($otherMethod)){
            $data = self::handleData($data, $otherMethod, self::$otherModelObj);
        }
        if (!empty($otherMethods)){
            $data = self::handleData($data, $otherMethods, self::$otherModelObjs);
        }
        return $data;
    }

    /**
     * 实际处理模型数据方法
     * @param $data
     * @param $method
     * @param $obj
     * @return array
     */
    public static function handleData($data, $method, $obj)
    {
        foreach ($method as $v){
            //截取方法名前三位
            $head = mb_substr($v, 0,3);
            //截取方法名后四位
            $bottom = mb_substr($v, -4);

            if ($head == 'get' && $bottom == 'Attr'){
                $field = strtolower(str_replace([$head,$bottom],'', $v));
                if(count($data) == count($data,1)){
                    if (isset($data[$field])){
                        $data[$field] = $obj->$v($data[$field]);
                    }
                }else{
                    foreach ($data as $ks => $va){
                        if (isset($va[$field])){
                            $data[$ks][$field] = $obj->$v($va[$field]);
                        }
                    }
                }
            }
        }
        return $data;
    }

    /**
     * 获取 model 表名和对象
     */
    private static function handleTable()
    {
        $string = get_called_class();
        $obj = new $string;
        $info = get_object_vars($obj);
        if (isset($info['tables']) && !empty($info['tables'])){
            self::$modelObj = $obj;
            self::$table = $info['tables'];
        }
    }

    /**
     * 清空条件属性
     */
    private static function clearParam()
    {
        self::$where = null;
        self::$join = null;
        self::$filed = null;
        self::$group = null;
        self::$order = null;
        self::$alias = null;
//        self::$table = null;
        self::$limit = null;
    }

    /**
     * 组装条件属性
     * @return array
     */
    private static function assembleField()
    {
        $arr['field'] = self::$filed;
        $arr['table'] = self::$table;
        $arr['alias'] = self::$alias;
        $arr['join'] = self::$join;
        $arr['where'] = self::$where;
        $arr['group'] = self::$group;
        $arr['order'] = self::$order;
        $arr['limit'] = self::$limit;
        return $arr;
    }
}